
import java.util.*;

public class RBot {
    // The DoTurn function is where your code goes. The PlanetWars object
    // contains the state of the game, including information about all planets
    // and fleets that currently exist. Inside this function, you issue orders
    // using the pw.IssueOrder() function. For example, to send 10 ships from
    // planet 3 to planet 8, you would say pw.IssueOrder(3, 8, 10).
    //
    // There is already a basic strategy in place here. You can use it as a
    // starting point, or you can throw it out entirely and replace it with
    // your own. Check out the tutorials and articles on the contest website at
    // http://www.ai-contest.com/resources.

    public static void DoTurn(PlanetWars pw, long startTime) {
        //double strengthWeight = 50.0 / pw.NumShips(1);
        int myShips = pw.NumShips(1);
        int enemyShips = pw.NumShips(2);
        int neutralShips = pw.NumShips(3);
        int totalShipsInGame = myShips + enemyShips + neutralShips;
        double myShipsRatio = (double) totalShipsInGame / myShips;
        double strengthWeight = .01 * myShipsRatio;
        double growthWeight = 10.0;
        if (pw.Turn() < 5) {
            growthWeight = 1.0;
        }
        double distanceWeight = 10.0;
        int numberOfPlanetsToAttack = 10;
        int totalPlanets = pw.Planets().size();
        int totalMyPlanets = pw.MyPlanets().size();
        int totalEnemyPlanets = pw.EnemyPlanets().size();

        double shipsRatio = (double) myShips / enemyShips;
        double planetsRatio = (double) totalMyPlanets / totalEnemyPlanets;
        double mapSize = pw.MapSize();

        boolean attackMode = false;
//        if (pw.Production(1) > pw.Production(2) && pw.NumShips(1) > pw.NumShips(2)) {
//            strengthWeight = .1;
//            attackMode = true;
//        } else if (pw.NumShips(0) < pw.NumShips(1) + pw.NumShips(2)) {
//            strengthWeight = .001;
//        } else {
//            strengthWeight = .01;
//        }

        //numberOfPlanetsToAttack = (int) (shipsRatio * 5 + planetsRatio * 5 + 2);


        Coord myCenter = pw.CenterOfPlanets(pw.MyPlanets());
        Coord enemyCenter = pw.CenterOfPlanets(pw.EnemyPlanets());
        Planet fakeEnemyPlanet = new Planet(-1, -1, -1, -1, enemyCenter.X(), enemyCenter.Y());

        //reinforcement phase
        List<Planet> myPlanetsByGrowth = pw.PlanetsSortedByGrowth(pw.MyPlanets());
        List<Planet> myPlanetsByStrength = pw.PlanetsSortedByNetStrength(pw.MyPlanets());
        //for each of my planets, starting with the high growth ones
        if ((System.nanoTime() - startTime) < 500000000) {
            for (Planet dest : myPlanetsByGrowth) {
                int shipsToDest = 0;
                int destStrength = pw.PlanetNetStrength(dest);
                //if i'm in danger of losing the planet, i need to reinforce it
                if (destStrength < 1) {
                    pw.Log("need_to_reinforce:");
                    pw.Log(Integer.toString(dest.PlanetID()));
                    //starting by looking at close planets
                    for (int i = 0; i < mapSize; i++) {
                        pw.Log("***radius:");
                        pw.Log(Integer.toString(i));
                        List<Planet> defensePlanets = new ArrayList<Planet>();
                        List<Integer> defenseShips = new ArrayList<Integer>();
                        int totalShips = 0;
                        List<Planet> closePlanets = pw.PlanetsWithinRadius(dest, i, myPlanetsByStrength);
                        int totalIncoming = 0;
                        //for each planet in the close planets, check to see if it has ships to spare
                        for (Planet source : closePlanets) {
                            if (source.PlanetID() != dest.PlanetID()) {
                                pw.Log("potential_source:");
                                pw.Log(Integer.toString(source.PlanetID()));
                                int strength = pw.PlanetNetStrength(source);
                                List<Fleet> friendlyFleets = pw.FriendlyFleets(pw.FleetsGoingToPlanet(source));
                                int incomingShips = pw.NumShips(friendlyFleets);
                                totalIncoming += incomingShips;
                                if (strength > 1) {
                                    int ships = source.NumShips() - 1;
                                    if (ships > 0) {
                                        totalShips += ships;
                                        defenseShips.add(ships);
                                        defensePlanets.add(source);
                                    }
                                }
                            }
                        }
                        boolean orderCached = false;
                        pw.Log("total_ships:");
                        pw.Log(Integer.toString(totalShips));
                        pw.Log("destination strength:");
                        pw.Log(Integer.toString(destStrength));



                        if (destStrength < 1 && totalShips + totalIncoming > ((-1) * destStrength) / .25) {
                            for (int j = 0; j < defensePlanets.size(); j++) {
                                Planet source = defensePlanets.get(j);
                                int numShips = defenseShips.get(j);
                                if (source.NumShips() > numShips && pw.PlanetNetStrength(source) - numShips > 1 && source.NumShips() - pw.NumShips(pw.FleetsGoingToPlanet(dest, pw.EnemyFleets())) > 1) {
                                    pw.Log("reinforcement:");
                                    pw.CacheOrder(source, dest, numShips);
                                    shipsToDest += numShips;
                                    orderCached = true;
                                }
                            }
                            destStrength = pw.PlanetNetStrength(dest);
                            if (orderCached && destStrength < 1) {
                                pw.Log("breaking:");
                                break;
                            }
                        }
                    }
                    //pw.Log("cant_reinforce!");
                }
            }
        }

        //attack phase
        if ((System.nanoTime() - startTime) < 500000000) {
//            List<Planet> targets;
//            if (attackMode) {
//                targets = pw.EnemyPlanets();
//            } else {
//                targets = pw.NotMyPlanets();
//            }
//            //List<Planet> planetsByValue = pw.PlanetsSortedByGrowth(targets);
//            List<Planet> planetsByValue = pw.PlanetsSortedByValue(myCenter, pw.NotMyPlanets(), distanceWeight, growthWeight, strengthWeight);
//            List<Planet> firstNPlanetsByValue = pw.FirstNPlanets(planetsByValue, numberOfPlanetsToAttack);
//            for (Planet destination : firstNPlanetsByValue) {
//                List<Planet> myPlanetsByDistance = pw.PlanetsSortedByDistance(destination, pw.MyPlanets());
//                if (destination.NumShips() < pw.AveragePlanetStrength(pw.Planets()) * .5) {
//                    for (Planet source : myPlanetsByDistance) {
//                        int shipsToSend = (-1) * (pw.PredictedStrength(destination, pw.Distance(destination, source)) - 2);
//                        //int shipsToSend = Math.abs(pw.PlanetNetStrengthPlusGrowthTimesDistance(source, destination)) + 2;
//                        //int shipsToSend = Math.abs(pw.PlanetNetStrength(destination)) + 2;
//                        if (shipsToSend > source.NumShips()) {
//                            shipsToSend = (int) ((double) source.NumShips() / totalMyPlanets);
//                            shipsToSend = 0;
//                        }
//                        //if (shipsToSend > 0 && pw.PredictedStrength(source, myCenter.Distance(enemyCenter)) > 0) {
//                        //if (shipsToSend > 0 && pw.PlanetNetStrength(source) > 0) {
//                        if (shipsToSend > 0 && source != destination) {
//                            if (destination.Owner() != 1 && pw.PlanetNetStrength(destination) < 1) {
//                                if (pw.PlanetNetStrength(source) - shipsToSend > 0) {
//                                    pw.Log("attack");
//                                    pw.CacheOrder(source, destination, shipsToSend);
//                                }
//                            }
//                        }
//                    }
//                }
//            }
            //attack phase
            List<Planet> planetsByValue = pw.PlanetsSortedByValue(myCenter, pw.NotMyPlanets(), distanceWeight, growthWeight, strengthWeight);
            List<Planet> firstNPlanetsByValue = pw.FirstNPlanets(planetsByValue, numberOfPlanetsToAttack);
            for (Planet target : firstNPlanetsByValue) {
                List<Planet> myPlanetsByDistance = pw.PlanetsSortedByDistance(target, pw.MyPlanets());
                for (Planet source : myPlanetsByDistance) {
                    int shipsToSend = (-1) * (pw.PredictedStrength(target, pw.Distance(target, source)) - 2);
                    //int shipsToSend = Math.abs(pw.PlanetNetStrengthPlusGrowthTimesDistance(source, target)) + 2;
                    //int shipsToSend = Math.abs(pw.PlanetNetStrength(target)) + 2;
                    if (shipsToSend > source.NumShips()) {
                        //shipsToSend = (int) ((double) source.NumShips() / totalMyPlanets);
                        shipsToSend = 0;
                    }
                    //if (shipsToSend > 0 && pw.PredictedStrength(source, myCenter.Distance(enemyCenter)) > 0) {
                    //if (shipsToSend > 0 && pw.PlanetNetStrength(source) > 0) {
                    if (shipsToSend > 0 && source != target) {
                        if (target.Owner() != 1 && pw.PlanetNetStrength(target) < 1) {
                            boolean planetLost = false;
                            if (pw.EnemyPlanets().size() > 0) {
                                Planet closestEnemy = pw.ClosestTo(source, pw.EnemyPlanets());
                                int distanceToClosestEnemy = source.GetDistance(closestEnemy);
                                for (int strength : pw.PredictedStrengthOverNTurns(source, distanceToClosestEnemy)) {
                                    if (strength - shipsToSend < 1) {
                                        planetLost = true;
                                    }
                                }
                            }
                            if (!planetLost) {
                                pw.Log("attack:");
                                if (target.GrowthRate() > 0 && pw.PlanetNetStrength(source) - shipsToSend > 50 && source.NumShips() - pw.NumShips(pw.FleetsGoingToPlanet(target, pw.EnemyFleets())) > 1) {
                                    pw.CacheOrder(source, target, shipsToSend);
                                }
                            }
                        }
                    }
                }
            }
        }

        //harassment phase
        if (pw.Production(1) > pw.Production(2) || pw.Turn() > 100) {
            if ((System.nanoTime() - startTime) < 500000000) {
                //List<Planet> enemyPlanetsByValue = pw.PlanetsSortedByValue(myCenter, pw.EnemyPlanets(), distanceWeight, growthWeight, strengthWeight);
                List<Planet> enemyPlanetsByValue = pw.PlanetsSortedByNetStrength(pw.EnemyPlanets());
                List<Planet> firstNEnemyPlanetsByValue = pw.FirstNPlanets(enemyPlanetsByValue, 1);
                for (Planet target : firstNEnemyPlanetsByValue) {
                    List<Planet> myPlanetsByDistance = pw.PlanetsSortedByDistance(target, pw.MyPlanets());
                    for (Planet source : myPlanetsByDistance) {
                        //int distanceToTarget = pw.Distance(source, target);
                        //if (pw.PredictedStrength(target, distanceToTarget) < 1) {
                        if (pw.PlanetNetStrengthPlusGrowthTimesDistance(source, target) < 1) {
                            //int shipsToSend = (Math.abs((pw.PredictedStrength(target, pw.Distance(target, source)) - 2) / 2)) + 1;
                            int shipsToSend = (-1) * (pw.PlanetNetStrength(target) + 2);
                            if (shipsToSend > source.NumShips() || shipsToSend <= 0) {
                                shipsToSend = (int) ((double) source.NumShips() / 2) - 1;
                                //shipsToSend = 1;
                            }
                            if (shipsToSend > 0) {
                                boolean planetLost = false;
                                if (pw.EnemyPlanets().size() > 0) {
                                    Planet closestEnemy = pw.ClosestTo(source, pw.EnemyPlanets());
                                    int distanceToClosestEnemy = source.GetDistance(closestEnemy);
                                    for (int strength : pw.PredictedStrengthOverNTurns(source, distanceToClosestEnemy)) {
                                        if (strength - shipsToSend < 1) {
                                            planetLost = true;
                                        }
                                    }
                                }
                                if (!planetLost) {
                                    if (target.GrowthRate() > 0 && pw.PlanetNetStrength(source) - shipsToSend > 50 && source.NumShips() - pw.NumShips(pw.FleetsGoingToPlanet(target, pw.EnemyFleets())) > 1) {
                                        pw.Log("harass:");
                                        pw.CacheOrder(source, target, shipsToSend);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        //move ships closer to the enemy
        //for (Planet source : pw.FirstNPlanets(pw.PlanetsSortedByNetStrength(pw.Planets()), numberOfPlanetsToAttack)) {
        if ((System.nanoTime() - startTime) < 500000000) {
            for (Planet source : pw.PlanetsSortedByGrowth(pw.MyPlanets())) {
                if ((System.nanoTime() - startTime) < 500000000) {
                    int strength = pw.PlanetNetStrength(source);
                    int distanceFromSourceToEnemy = pw.Distance(source, fakeEnemyPlanet);
                    int distanceFromSourceToClosestEnemyPlanet = pw.Distance(source, pw.ClosestTo(source, pw.EnemyPlanets()));
                    //int strength = pw.PredictedStrength(source, distanceFromSourceToClosestEnemyPlanet);
                    double enemyDirection = pw.Angle(enemyCenter.X() - source.X(), enemyCenter.Y() - source.Y());
                    if (strength > 1) {
                        List<Planet> closePlanets = pw.PlanetsSortedByDistance(source, pw.MyPlanets());
                        for (Planet dest : closePlanets) {
                            if (!((System.nanoTime() - startTime) < 500000000)) {
                                break;
                            }
                            strength = pw.PlanetNetStrength(source);
                            if (source.PlanetID() != dest.PlanetID()) {
                                double destDirection = pw.Angle(dest.X() - source.X(), dest.Y() - source.Y());
                                int distanceFromDestToEnemy = pw.Distance(dest, fakeEnemyPlanet);
                                int distanceFromSourceToDest = pw.Distance(source, dest);
                                //if (destDirection < enemyDirection + 60 && destDirection > enemyDirection - 60 && pw.Distance(source, dest) < mapSize/4) {
                                if (distanceFromDestToEnemy < distanceFromSourceToEnemy) {
                                    if (!pw.ContainsEnemyPlanet(pw.PlanetsWithinRadius(source, distanceFromSourceToDest, pw.NotMyPlanets()))) {
                                        int shipsToSend = strength / 2;
                                        if (shipsToSend > source.NumShips()) {
                                            shipsToSend = source.NumShips() / 2;
                                        }
                                        boolean planetLost = false;
                                        if (pw.EnemyPlanets().size() > 0) {
                                            Planet closestEnemy = pw.ClosestTo(source, pw.EnemyPlanets());
                                            int distanceToClosestEnemy = source.GetDistance(closestEnemy);
                                            for (int pstrength : pw.PredictedStrengthOverNTurns(source, distanceToClosestEnemy)) {
                                                if (pstrength - shipsToSend < 1) {
                                                    planetLost = true;
                                                }
                                            }
                                        }
                                        if (!planetLost) {
                                            if (shipsToSend > 0 && strength - shipsToSend > 1 && source.NumShips() - pw.NumShips(pw.FleetsGoingToPlanet(dest, pw.EnemyFleets())) > 1) {
                                                pw.Log("move_ships_up:");
                                                pw.CacheOrder(source, dest, shipsToSend);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                } else {
                    break;
                }

            }
        }
        pw.Log("time_elapsed:");
        pw.Log(Long.toString((System.nanoTime() - startTime)));

    }

    public static void main(String[] args) {
        PlanetWars pw = new PlanetWars();
        String line = "";
        String message = "";
        int c;
        try {
            while ((c = System.in.read()) >= 0) {
                switch (c) {
                    case '\n':
                        if (line.equals("go")) {
                            long startTime = System.nanoTime();
                            pw.ParseGameState(message);
                            DoTurn(pw, startTime);
                            pw.IssueCachedOrders();
                            pw.FinishTurn();
                            message = "";
                        } else {
                            message += line + "\n";
                        }
                        line = "";
                        break;
                    default:
                        line += (char) c;
                        break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace(System.out);
            // Owned.
        }
    }
}
